function cp=bgcm(pM,k1,k2,class,alp,beta,itnum,idl,L)
%
%  bgcm: bipartite graph-based consensus maximization among multiple
%        supervised and unsupervised models.
%        Given the outputs of multiple models on a target set, the
%        algorithm returns the consensus labels of the objects in the set.
%             
%  Input: 
%       pM-a matrix containing all the base models' outputs on the target set. 
%          Each column represent one model. You must place classification models
%           before clustering models.
%
%       k1-number of classification models, so columns 1:k1 in the matrix pM are the
%          results of classification models
%
%       k2-number of clustering models, so columns k1+1:k1+k2 in the matrix pM
%          are the results of clustering models
%
%       class-the number of classes in the problem
% 
%       alp-parameter alpha in the paper, usually set to 1 or 2
%
%       beta-parameter beta in the paper, usually greater than alp
%
%       itnum-number of iterations
%
%       idl-the row numer of the labeled objects in the target set, if you
%           do not have any labeled objects, simply set idl=[]
%
%       L-the class labels of the labeled objects, so the size of L and
%         that of idl should be the same, if you do not have any labeled
%         objects, simply set L=[]
%
%  Output:           
%       cp-the consensus label for all the objects in the target set
%
%==========================================================================
%
%
% An example:
%
%       %load the results of all the base models for Cora1 data set
%       directory='../data/cora/'; 
%       pM=load([directory,'mbase1.csv']); 
%
%       %unsupervised version
%       %the task has 3 classes, 2 classification models, 2 clustering
%       models. We set alp=2, beta=8 and itnum=30
%       idl=[]; L=[];
%       cp=bgcm(pM,2,2,3,2,8,30,idl,L);
%
%       %semi-supervised version
%       %load the labels of the target set
%       label=load([directory,'label1.csv']);
%       %randomly select a small portion as labeled objects from each class
%       [idl,L]=ransel(label,3,20);
%       %run the algorithm to get the consensus labels
%       cp=bgcm(pM,2,2,3,2,8,30,idl,L);
%

% get the number of objects and number groups
[n,m]=size(pM);
num_clust=(k1+k2)*class;
num_inst=n;

%initialization
link=zeros(num_clust,num_inst); % the adjacency matrix of the bipartite graph
b=zeros(num_clust,class); % the initial label assignment

%get the group-object adjacency matrix from classifier outputs
%assign initial probability to group nodes from classifiers
for i=1:k1
    for j=1:num_inst
        h=(i-1)*class+pM(j,i);
        link(h,j)=1;
        b(h,pM(j,i))=1;
    end
end

%get the group-object adjacency matrix from clustering outputs
for i=k1+1:k1+k2
    for j=1:num_inst
        h=(i-1)*class+pM(j,i);
        link(h,j)=1;
    end
end

%get the initial label of labeled objects
d=zeros(num_inst,class);
for i=1:length(idl)
    j=idl(i);
    d(j,L(i))=1;
end

%conditional probability of groups
q_clust=zeros(num_clust,class);

%conditional probability of objects
q_inst=zeros(num_inst,class);

%initialize the conditional probability of objects as uniform
for i=1:num_inst
    for h=1:class
        q_inst(i,h)=1/class;
    end
end

%vectors used in the updating formula
Hv=sum(b,2);
Hn=sum(d,2);
%labeled information
Y=b.*repmat(Hv,1,class);
F=d.*repmat(Hn,1,class);
%normalizing matrices
Dv=repmat((sum(link,2)+alp*Hv),1,class);
Dn=repmat((sum(link)'+beta*Hn),1,class);

%iteratively propagate the conditional probability among group nodes and object nodes
for m=1:itnum   
    q_clust=(link*q_inst+alp*Y)./Dv;
    q_inst=(link'*q_clust+beta*F)./Dn;
end

%for classification purpose, assign the class label with the highest probability to each example  
[tmp,cp]=max(q_inst,[],2);


